// Logging.cpp : implementation file
//

#include "stdafx.h"
#include "Logging.h"
#include "globals.h"
#include <fstream>

#ifdef _DEBUG
//#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CLogging

CLogging::CLogging()
{
	out = NULL;
}

CLogging::~CLogging()
{
	if (out)
	{
		out->close();
		delete out;
	}
}

/////////////////////////////////////////////////////////////////////////////
// CLogging Functions

ofstream* CLogging::InitLogging(char *ProgramDirectory, char *logname)
{
	char time[50];
	char logfile[MAX_PATH], oldfile[MAX_PATH];
	GetDateTime(time, 50);
	CString oldname = logname;
	oldname += "old";
	SPathSplit patharray;
	strcpy_s(patharray.oldname, MAX_PATH, ProgramDirectory);
	//_splitpath (ProgramDirectory, patharray.drive, patharray.dir, patharray.fname, patharray.ext);
	_splitpath_s(ProgramDirectory, patharray.drive, _MAX_DRIVE, patharray.dir, _MAX_DIR, patharray.fname, _MAX_FNAME, patharray.ext, _MAX_EXT );
	_makepath_s(logfile, MAX_PATH, patharray.drive, patharray.dir, logname, ".log"); 
	_makepath_s(oldfile, MAX_PATH, patharray.drive, patharray.dir, oldname, ".log"); 
	CopyFile(logfile, oldfile, FALSE);
	out = NULL;
	out = new ofstream(logfile, ios::trunc);
	if (out->fail())
		return NULL;
	*out << "Log Started " << time << endl;
	*out << "program exe path " << ProgramDirectory << endl;
	char tmp[50];
	CString cVersion = "                             ";
	GetVersion(&cVersion, 30);
	
	sprintf_s(tmp, 50, "Program Version %.3f", atof(cVersion)/1000);
	*out << tmp << endl;
	GetOSType(out);
	char str[256];
	memset(str, 0, 256);
	int Width = 7;
	int Div = 1024;
	char *divisor = "K";
	MEMORYSTATUSEX stat;
	stat.dwLength = sizeof (stat);
	GlobalMemoryStatusEx (&stat);
	*out << "Memory statistics" << endl;
	sprintf_s (str, 256, "%ld percent of memory is in use.", stat.dwMemoryLoad);
	*out << str << endl;
	sprintf_s (str, 256,  "There are %*ld total %sB of physical memory.", Width, stat.ullTotalPhys/Div, divisor);
	*out << str << endl;
	sprintf_s(str, 256, "There are %*ld free %sB of available physical memory.",  Width, stat.ullAvailPhys/Div, divisor);
	*out << str << endl;
	sprintf_s (str, 256, "There are %*ld total %sB of paging file.",     Width, stat.ullTotalPageFile/Div, divisor);
	*out << str << endl;
	sprintf_s (str, 256, "There are %*ld free %sB of available paging file.",      Width, stat.ullAvailPageFile/Div, divisor);
	*out << str << endl;
	sprintf_s (str, 256, "There are %*ld total %sB of virtual memory.",  Width, stat.ullTotalVirtual/Div, divisor);
	*out << str << endl;
	sprintf_s (str, 256, "There are %*ld free %sB of available virtual memory.",   Width, stat.ullAvailVirtual/Div, divisor);
	*out << str << endl;
	return out;
}


void CLogging::CloseLogging()
{
	if (out == NULL)
		return;
	char time[50];
	GetDateTime(time, 50);
	*out << "Log Finished " << time << endl;
	out->close();
	delete out;
	out = NULL;
}

void CLogging::GetDateTime(char *timebuf, int timesize)
{
	time_t today = time(NULL);
	tm tm_time; // = *localtime(&today);
	int error = _localtime32_s(&tm_time, (__time32_t*) &today);
	strftime(timebuf, timesize, "%#c", &tm_time);
}

//----------------------------------------------------------------------------------------------
// void GetOSType()
// Detect Operating type and return it via an enum integer.
// PARAMETERS:	OSVERSIONINFOEX *osvi - pointer to a OSVERSIONINFOEX struct
//
// RETURN -1 = error, 
//----------------------------------------------------------------------------------------------
void CLogging::GetOSType(ofstream *output)
{
	
	if (output == NULL)
		return;
	CString tmp;
	*output << "Operating System" << endl;
	tmp = ReadOperatingSystemStringFromRegistry("ProductName").GetBuffer(0);
	*output << tmp.GetBuffer(0);
	tmp.ReleaseBuffer();
	OSVERSIONINFO osvi;
    ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
    osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
    if (GetVersionEx ( (OSVERSIONINFO *) &osvi)) 
	{
		tmp.Format(" Version %d.%d (Build %d)", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);
		*output << tmp.GetBuffer(0) << endl;
		tmp.ReleaseBuffer();
	}
	return;
   *output << endl;
}

CString CLogging::ReadOperatingSystemStringFromRegistry(char *key)
{
	HKEY hKey;
	CString tmp;
	CString cBios;
	DWORD dwType;
	DWORD dwBufLen = MAX_PATH;
	tmp = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\";
	// Open the key
	if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, tmp, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
	{

		return "";
	}
	if (RegQueryValueEx( hKey, key, NULL, &dwType, (LPBYTE) cBios.GetBuffer(MAX_PATH), &dwBufLen) != ERROR_SUCCESS)
    {
		cBios.ReleaseBuffer();
		RegCloseKey(hKey);
		return "";
	}
	if(dwType==REG_MULTI_SZ)
	{
		RegCloseKey(hKey);
		TCHAR szResult[512] = _T("\0"); //512 is max REGSZ entry
		if(RegMultiRead(HKEY_LOCAL_MACHINE, tmp.GetBuffer(512), "VideoBiosDate", szResult,512)==0)
		{
			cBios = CString(szResult);
		}
		else
		{
			cBios = "";
		}
		tmp.ReleaseBuffer();
		return cBios;	
	}
	else
	{
		cBios.ReleaseBuffer();
		RegCloseKey(hKey);
	}
	return cBios;	
}

////////////////////////////////////////////////////////////
//     MULTI-STRING CODE MODIFICATION:  NEW METHOD
////////////////////////////////////////////////////////////
DWORD CLogging::RegMultiRead(HKEY hHive, LPTSTR szKey, LPTSTR szValue, LPTSTR szResult, size_t iResultSize)
{
       long lRet = 0;
       HKEY  hKey; 

       if (lRet = RegOpenKeyEx(hHive,szKey,0,KEY_EXECUTE,&hKey) == ERROR_SUCCESS)
       {
              DWORD dwType = 0;
              DWORD dwSize = (DWORD)iResultSize;
              DWORD dwCapacity = (DWORD)iResultSize;
              LPTSTR szData = new TCHAR[iResultSize+4*sizeof(TCHAR)]; 

              lRet = RegQueryValueEx(hKey,szValue,NULL,&dwType,(LPBYTE)szData,&dwSize);

              if( (lRet != ERROR_SUCCESS) || (dwSize > dwCapacity) || dwType != REG_MULTI_SZ )
              {
                     RegCloseKey(hHive);
                     delete[] szData;
                     return dwSize;
              }

              LPTSTR  szToken = NULL;
              LPTSTR  szTmp = new TCHAR[dwCapacity];
              _tcscpy_s (szTmp, dwCapacity, _T("\0")); 

              // Grab the first null-terminated string
              szToken = szData;
              while( szToken != NULL )
              {
                     // Copy the string out
                     _tcscat_s (szTmp, dwCapacity, szToken);

                     // Increment the token to the next string
                     szToken = szToken + _tcslen (szToken) + sizeof(TCHAR);

                     // If the next string isn't null, append a pipe
                     // to the target string.
                     if (_tcslen (szToken) > 0)
                           _tcscat_s (szTmp, dwCapacity, _T("|"));
                     else
                           szToken = NULL;
              }

              _tcscpy_s(szResult, iResultSize, szTmp);     
              delete[] szData;
              delete[] szTmp;
              RegCloseKey(hKey);
              RegCloseKey(hHive);
       }
       else
              return lRet;      

       return 0;
}